package top.codef.sqlfilter;

import java.util.stream.Stream;

import jakarta.persistence.criteria.Expression;
import top.codef.exceptions.JpaAmebaException;
import top.codef.sqlfilter.functional.SelectCondition;

public class Selectors {

	public static SelectCondition count(String field) {
		return (builder, path) -> builder.count(PathUtils.getPath(field, path));
	}

	public static SelectCondition select(String field) {
		return (builder, path) -> PathUtils.getPath(field, path);
	}

	@SuppressWarnings("unchecked")
	public static SelectCondition avg(String field) {
		return (builder, path) -> {
			var res = PathUtils.getPath(field, path);
			if (Number.class.isAssignableFrom(res.getJavaType())) {
				var numRes = (Expression<Number>) res;
				return builder.avg(numRes);
			} else
				throw new JpaAmebaException("the given fieldType cannot calculate avg");
		};
	}

	@SuppressWarnings("unchecked")
	public static SelectCondition max(String field) {
		return (builder, path) -> {
			var res = PathUtils.getPath(field, path);
			if (Number.class.isAssignableFrom(res.getJavaType())) {
				var numRes = (Expression<Number>) res;
				return builder.max(numRes);
			} else
				throw new JpaAmebaException("the given fieldType cannot calculate max");
		};
	}

	@SuppressWarnings("unchecked")
	public static SelectCondition abs(String field) {
		return (builder, path) -> {
			var res = PathUtils.getPath(field, path);
			if (Number.class.isAssignableFrom(res.getJavaType())) {
				var numRes = (Expression<? extends Number>) res;
				return builder.abs(numRes);
			} else {
				throw new JpaAmebaException("the given fieldType cannot calculate abs");
			}
		};
	}

	@SuppressWarnings("unchecked")
	public static SelectCondition sum(String field) {
		return (builder, path) -> {
			var res = PathUtils.getPath(field, path).alias("sumTotal");
//			if (Number.class.isAssignableFrom(res.getJavaType())) {
			var numRes = (Expression<? extends Number>) res;
			return builder.sum(numRes);
//			} else {
//				throw new JpaAmebaException("the given fieldType cannot calculate sum");
//			}
		};
	}

	public static SelectCondition distinct(String field) {
		return (builder, path) -> {
			var res = PathUtils.getPath(field, path);
			return builder.function("distinct", String.class, res);
		};
	}

	public static <T> SelectCondition function(String functionName, Class<T> returnClass, String... field) {
		return (builder, path) -> {
			return builder.function(functionName, returnClass,
					Stream.of(field).map(x -> PathUtils.getPath(x, path)).toArray(Expression<?>[]::new));
		};
	}

	public static <T> SelectCondition distinctCount(String field) {
		return (builder, path) -> {
			return builder.countDistinct(PathUtils.getPath(field, path));
		};
	}

//	private static Path<?> path(Path<?> path, String field) {
//		var result = path;
//		for (String element : field.split("\\.")) {
//			result = result.get(element);
//		}
//		return result;
//	}
}
